package ua.yandex.shad.tempseries;


public class TemperatureSeriesAnalysis {

    private final double[] temperatureSeries;

    private static final int MIN_TEMPERATURE = -273;
    private static final int MIN_NEED_FORECAST_LENGTH = 10;

    public TemperatureSeriesAnalysis(final double[] temperatureSeries) {
        for (double temperature : temperatureSeries) {
            if (temperature < MIN_TEMPERATURE) {
                throw new IllegalTemperatureValueException("Temperature cannot be less than -273C");
            }
        }
        this.temperatureSeries = temperatureSeries.clone();
    }

    private boolean isSeriesEmpty() {
        return (temperatureSeries.length == 0);
    }

   public double calcAverageTemp() {
        if (isSeriesEmpty()) {
            return 0;
        }
        double sum = 0;
        for (double temperature : temperatureSeries) {
            sum += temperature;
        }
        int length = (temperatureSeries.length);
        return sum / length;
    }    

    public double calcTempDeviation() {
        if (isSeriesEmpty()) {
            return 0;
        }
        double sum = 0;
        int length = temperatureSeries.length;
        for (double temperature : temperatureSeries) {
            sum += temperature * temperature;
        }
        
        double avgTemp = calcAverageTemp();
        sum -=  length * avgTemp * avgTemp;
        
        return sum / (length);
    }

    public double findTempClosestToZero() {
        return findTempClosestToValue(0);
    }

    public double findTempClosestToValue(final double tempValue) {
        if (isSeriesEmpty()) {
            return 0;
        }
        double closestValue = temperatureSeries[0];
        for (double temperature : temperatureSeries) {
            if (Math.abs(temperature - tempValue) <= Math.abs(closestValue - tempValue)) {
                if (Math.abs(temperature - tempValue) < Math.abs(closestValue - tempValue)) {
                     closestValue = temperature;
                }
                else
                    if (temperature > tempValue) {
                        closestValue = temperature;
                    }
            }
        }
        return closestValue;
    }

    private double[] findTempsThen(final double tempValue,final int sign){
        if (isSeriesEmpty()){
            return new double[]{};
        }
        double[] temps;
        int count = 0;
        for (double temperature : temperatureSeries) {
            if (temperature * sign < tempValue * sign) {
                count++;
            }
        }
        temps = new double[count];
        count = 0;
        for (double temperature : temperatureSeries) {
            if (temperature * sign < tempValue * sign) {
                temps[count++] = temperature;   
            }
        }
        return temps;
    }

    public double[] findTempsLessThen(final double tempValue){
        return findTempsThen(tempValue , 1);
    }

    public double[] findTempsGreaterThen(final double tempValue){
        return findTempsThen(tempValue , -1);
    }

    public double[] forecatsTemp(){
        if (temperatureSeries.length < MIN_NEED_FORECAST_LENGTH){
            throw new NotEnoughValuesToForecastException("Does not enough values to forecast temperature");
        }
        return new double[]{};
    }
    
}
